<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=utf-8">
<title>外文翻译译文</title>
<style type="text/css" media="print">
article.paging{page-break-before:always;}
</style>
<style>
	h1{text-align:center;}

	body{font-family:"宋体";line-height: 20pt;}
	h1,h2,h3,h4{font-family:"黑体";}
</style>
</head>

<body>
	<article>
		<h1 >避免内存泄漏(Avoiding Memory Leaks)</h1>
		<div>
			<p>
				Android程序，至少对于T-Mobile G1来说，堆区限制在16M。这对于电话来说可是说是很多的内存，
				但是对于某些开发者来说又算是很少。虽然你并没有打算使用所有的内存，你应该让你的程序使用尽可能少的内存，以避免你的应用被杀死。Android能够在内存中保留的程序越多，对于用户来说在任意两个程序之间切换的速度就越快！在我的工作中，在Android中我所遇到的关于内存泄漏的问题，大多数都是因为同样的错误：保存一个对于
				<code>Context</code>的长期引用。
			</p>

			<div>
				在android中，一个
				<code>Context</code>
				可用于很多操作，但是最多的是加载资源和访问资源。
				这就是为什么所以的小部件都在他们的构造函数中接收一个Context参数。在一个普通的android应用中， 你通常有两种类型的
				<code>Context</code>,Activity和Application.通常开发者传递到需要一个<code>Context</code>
						的类中和方法中去的是第一个：
						<pre>
            @Override
            protected void onCreate(Bundle state){
                super.onCreate(state);
                TextView label = new TextView(this);
                label.setText("Leaks are bad");
                
                setContentView(label);
            }
        </pre>
						<p>
							这意味着那个view有一个对于整个activity的引用即对于你的activty中的任何东西;
							通常整个view层级和所有的资源。因此，如果你漏泄了
							<code>Context</code>
							("泄漏”是指你保存了一个指向它的引用，从而阻止了GC回收它。），你就泄漏了很多的内存。
							如果你不小心的话，泄漏一整个activity是很容易的。
						</p>
			</div>

			<div>
				<p>当屏幕方向改变的时候，默认情况下系统将销毁当前的activity同时创建一个新的并保存它的状态。
					执行这些操作的时候，Android将从资源中重新加载应用的UI。现在想像一下应用中有很大的图片，你不想在每次屏幕旋转的时候重新加载它，最简单的保存它并不在每次旋转的时候重新加载的方式就是将其保存为一个静态字段:


				
				<pre>
private static Drawable sBackground;

@Override
protected void onCreate(Bundle state){
    super.onCreate(state);
    
    TextView label = new TextView(this);
    label.setText("Leaks are bad");
    if(sBackground == null){
        sBackground = getDrawable(R.drawable.large_bitmap);
    }
    label.setBackgroundDrawable(sBackground);
    setContentView(label);
}
            </pre>
				这个代码很快，同时也错得可以;它在第一次屏幕方向改变的时候泄漏了第一次创建的activity。当一个
				<code>Drawable</code>
				依附于一个view的时候这个view被设置为这个drawable的
				<code>callback</code>
				.如上面的代码片段所示，那意味着,这个drawable有一个指向TextView的引用，而同时TextView有一个指向activity(即
				<code>Context</code>
				)，而这个
				<code>Context</code>
				又引用了很多东西（取决于你的代码）。
				</p>
				<p>
					这是一个很简单的关于泄漏
					<code>Context</code>
					的类，你可以在
					<quote>Home screen's source code</quote>
					(查找
					<code>unbindDrawables()</code>
					方法）中看到如何处理这种问题的，当这个activity要被销毁的时候设置一个保存drawable的回调函数为null。更有意思的是，当你创建了一个泄漏链的时候，这个链会让你的应用内存溢出更快。
				</p>
				<p>
					这是有两个避免Context相关的内存泄漏的简单的方法。最明显的一个就是，避免让context离开在它的自己的范围。上面的例子中，展示了一个静态引用，但是它的内部类及对于外部类的隐式引用同样危险。第二个解决方案就是
					使用
					<code>Application</code>
					context.这个context将会一直存活直到你的应用退出。它并不依赖activity的生命同期。如果打算保存一个需要长期引用的对象并且需要一个context，请记得使用application
					context. 你可以通过调用
					<code>Context.getApplicationContext()</code>
					或者
					<code>Activity.getApplication()</code>
				</p>

			</div>

		</div>

		<div>
			总结，为了避免context相关的内在泄漏，请记住以下几点：
			<ul>
				<li>不要保存对context-activity的长期引用(一个对一个activity的引用应该与activity本身具有相同的生存周期)</li>
				<li>尽量使用context-application而不是一个context-activity</li>
				<li>避免在一个activity中的非静态内部类，如果你没有控制他们的生存周期的话，使用一个静态内部类并将其保存一个到activity的弱引用。这个解决方法是保存一个对于外部类的弱引用，正如在<code>ViewRoot</code>中所做的一样，它的W内部类.
				</li>
				<li>垃圾收集器并不是内在泄漏的保险</li>
			</ul>
		</div>
	</article>
	<!--  Avoiding Memory Leaks -->
	<article class="paging">
		<h1>Android的多任务机制(Multitasking the Android Way)</h1>
		<div>android在允许多个应用同时运行的方式是非常独特的。来自其它平台的开发者将发现这种方式非常独特。
			理解它的行为将有利于将程序设计得运行得更好，和与android平台无缝集成。这篇文章讲解了android多任务设计的缘由;和它对程序如何运行的影响，以及如果最大限度的利用android的特性。
		</div>
		<div>
			<h2>设计考虑</h2>
			<p>手机设备有技术限制，同时用户体验也不同于web系统及桌面应用。下面是在我们设计android多任务时四个关键的限制:</p>
			<ul>
				<li>当用户使用完应用时我们不需要用户去关闭它。这样一个模式在一个用户整天不同的与各种不同的应用打交道的环境。</li>
				<li>手机设备没有很大的交换空间，因此在内存使用的限制上有硬性的限制。Robert
					Love在这个方面有一篇很好的文章(http://blog.rlove.org/2010/04/why-ipad-and-iphone-dont-support.html)
				</li>
				<li>
					应用程序在手机设备上的切换是有很极端的限制的;我们的目标是在1秒内启动一个新的应用。当用户只在几个应用之间切换时，这一点特别重要，例如如果用户在看视频的时候切换去看一条新短信，然后返回继续看视频。如果在这种情况下等待比较久的话，将会很快使用户不满。
				</li>
				<li>这些可用的api要能够很高效的用于写内置的Google应用，作为我们"所有应用都是平等创建“的原则。
					这意味着后台运行的音乐，数据同步，GPS导航，和应用下载都是通过同样的即第三方开发者可用的API来实现</li>
			</ul>
			<p>
				上面的头两条需求突出了一个效益冲突。我们并不想用户去担心关闭他们的应用，但是却看它看起来所有的应用都是一直在运行。同时，手机设备可用内存有限，因此系统将退化并开始衰减当内在供不就求的时候;而一个桌面电脑，有交换分区，反过来说，当需要在交换空间进行内存时分页时，它将变慢。这个相互矛盾的限制是anroid设计的关键动机。
			</p>
		</div>

		<div>
			<h2>应用什么时候停止?</h2>
			<p>一个关于android多线程通常的误解是关于一个进程与一个应用的区别.
				在android中它们并不是一个紧密耦合的实体:对于用户应用看起来没有一个实际的进程在运行此应用;
				多个应用可以共享进程,或者一个应用根据它的需要使用多个进程;甚至当一个应用没有在什么事情时应用的进程也一直在android中存在.
				实际上你可以看到一个应用进程的运行并不意味着这个应用正在运行或者做什么事.它只是就在哪里而已,因为也许android会在某个时候需要它,
				或者因为最好是保存它以便它再次使用.同理,你也许会离开一个应用,然后又返回刚才离开的地方,在你离开的时候,android也许会因为某些
				事件丢弃这个线程.</p>
			<p>
				了解android应用处理应用程序的关键是应用并没有关闭之后并没有完全的清理,当用户离开一个应用的时候,它的进程也许会保存在后台中,
				以便需要的话再次工作(例如,下载网页),
				同时在用户需要的时候马上回到前台.如果设备不会内存溢出,那android将保存所有这些进程,看起来这些进程都是一直在运行.</p>
			<p>
				当然,内存是有限的,为了达到此目的,android必需决定什么时候清理不需要的线程.这就是android进程生命周期的来历.
				,用户判断进程重要性的规则,因此次要的将关闭.这条规则中重要性基于两点,一是进程对于当前用户体验的重要性,二是它距离上次被用户使用多久了.

			</p>
			<p>
				一旦android决定关闭一个进程,它会很暴力的仅仅是杀掉它.内核将立即释放此进程占用的资源,而不是给进程一个礼貌的退出请求再等到它响应.
				这种机制有利于方便的避免更严重的内存溢出问题.</p>
			<p>如果用户再次返回到已经被杀死的应用中,Android需要一种能够重新启动应用到杀死前的状态,
				保留"所有的应用仿佛都是在同时运行"的体验.这是通过保存用户注意到的应用,并且在重新启动应用的时候,
				恢复用户最后看到的状态.这些最后的状态是当用户离开这些应用时保存,而不是被杀死时,因此内核在稍后能够轻松的杀死进程
				而不用担心应用能够在那一点上是否能正确响应.</p>
			<p>在某种意义来说,android的进程管理也可以看作一种交换空间的形式:
				应用进程代表一定数量使用的内存,当内存不够时,一些进程被杀死(被交换出);当再次需要这些进程时,他们能够用它们最后的状态重新启动(交换进).
			</p>
		</div>

		<div>
			<h2>显式的在后台运行</h2>
			<p>到目前为止,我们有一种让应用在后台隐式工作的方式--只要这个应用没有被android在常规内存管理中杀死.
				这对于在后台加载网页来说足够了,但是如果应付刚性的需要呢?如后台播放音乐,数据同步,定位,闹钟等等.</p>
			<p>
				对于这些任务,这些应用需要以某种方式来告诉android说"我想要在后台运行",对于此,应用有两种主要的设施可用,
				即可以在manifest中声明的两种组件:
				<code>broadcast receivers</code>
				和
				<code>services</code>
			</p>
			<div>
				<h3>Broadcast Receivers</h3>
				<p>
					当某些事情发生时,一个BroadcastReceiver可以让一个应用在后台运行一小段时间. 它可以用来构建更高级的基础设施;例如
					<code>AlarmManager</code>
					允许一个应用去在某个时间发送一个广播(broadcast ,一个
					<code>LocationManager</code>
					在检测到位置上有意义的改变时发送一个广播.因为关于
					<code>receiver</code>
					的信息是应用 清单的一部分.
					所以android能够找到并启动这个应用就算它并没有在运行;当然如果它已经有一个进程在后台可用,那么广播将 很快地直接转发到进程中去.
				</p>
				<p>
					当处理一个广播(broadcast)时,系统给应用分配了一个固定的时间(现在是10秒)用于应用的操作.如果它在哪个时间没有完成操作,
					此应用将被认为是有异常操作的,它的进程将被打进后台状态并且如果在需要内存的时候被杀死.</p>
				<p>广播接收者(Broadcast
					receivers)非常适合在一些外部条件触发时做一些简单的片段操作,例如当新的GPS位置设定时向用户
					投递一个新的通知.它们是非常轻量的,因为这个应用的进程只需要在接收到广播的时候进行些操作.因为他们只运行一定的时间,而且有很可靠的保证在运行时不被杀死.
					然而他们不适合进行任何不知道时间的操作,例如网络操作.</p>
			</div>

			<div>
				<h3>Services</h3>
				<p>
					一个服务(Service)允许一个应用在后台长期运行的操作.实际上service还能够提供很多其它的功能,但是在这里的讨论
					基于这样的一个基本目的---应用需要在后台持续运行,直到操作完成.一个应用可以通过显式的启动和停止service来控制它.</p>
				<p>
					然而service没有提供一个富C/S模型,它的使用是可选的.在启动一个应用的service的时候,android只是简单的在进程中实例化
					这个组件来提供其context.然而他稍后的使用取决于应用;它能在一个服务中放置所需要的代码而不用去跟应用的其它部分交互,
					在与其它应用部分共享的单例对象中进行调用,直接在需要的地方取得
					<code>Service</code>
					的实例.如果需要的话可以通过一个 RPC协议来在其它进程中运行.
				</p>
				<p>对于服务的进程管理不同于broadcast receiver(广播接收者),因为任意的服务可以请求运行任意长的时间.
					有可能没有足够的内存来满足所有请求运行的服务,结果,并不能保证他们能够一直运行.</p>
				<p>如果只有一点内存,进程中的服务将会向后台进程一新被马上杀死.但是,如果可能的话android会知道哪些服务
					还希望继续运行,当有足够的内存可用的时候,系统将自动重新它们.例如,如果用户浏览一个网页,这需要很大的内存,
					android会结束后台的如同步进程,直到浏览器内存使用降低.</p>
				<p>
					服务可以通过与android系统协商将自己作为一个"前台"进程以改变这种默认的行为.这将会使service处于一种"请别结束我"
					的状态,但是需要通知用户依然在运行.对于后台音乐播放或者车载导航等service这很有用,用户将清楚的知道他们正在运行.
					当你在播放音乐时同时浏览网页,你能够在状态条中看到正在播放的曲目,android不会杀掉这些服务,但是作为一个默认的约定,
					确保用户知道他们,并且在需要的时候能够显式的关闭他们.</p>
			</div>

			<div>
				<h3>通用组件的价值</h3>
				<p>android的通用broadcast
					receiver（广播接收者）及service组件能够让开发者创建丰富多样的高效后台操作，包含开发者原来从来没有想到过的。在android1.0中，他们用于实现几乎内置的及Google
					App提供的所有应用的后台操作:
				<ul>
					<li>允许用户离开音乐应用后音乐播放还在一个服务中运行。</li>
					<li>闹钟用一个闹钟管理者调度广播接收者，以达到在下次设定的闹钟时刻响起。</li>
					<li>日历应用同样调度了一个闹钟在下一个日历事件中适当的时候来显示或者更新通知</li>
					<li>后台文件下载以一个服务来实现，当有下载来处理时</li>
					<li>E-mail应用也在使用了闹钟调度来在一个以一个固定的时间频率来检查并取回新邮件。</li>
					<li>Google的应维护了一个从网络推送通知的服务;它还会向单独的应用依次发出广播当它们需要去做如同步联系人的事件时。</li>
				</ul>
				</p>

				<p>随着平台的演变，这些基本的组件用来实现更多主要的开发特性:
				<ul>
					<li>开发者用Service来实现输入法，android管理服务作为当前的输入法</li>
					<li>窗口小部件(Application
						widget）是广播接收者，当需要与它们交互时，android向它们发送广播。这让窗口小部件变得很轻量，不需要它们的应用还一直在运行。</li>
					<li>附近功能作为一个服务来实现，android让它一直运行着，同时发送与用户交互相关的信息。</li>
					<li>在android2.0中推出的Sync
						adapter（同步适配器),作为一个运行在后台的服务-当某一些数据需要同步时，</li>
					<li>当一个动态壁纸被用户选择时，android将它作为一个服务在后台启动。</li>
				</ul>
				</p>

			</div>

		</div>
	</article>
	<!-- end Multitasking the Android Way -->
	<article class="paging">
		<h1>Android绘制View的方式</h1>
		<p>
			当一个Activity接收到焦点的时候，它将绘制它的布局(layout)。Android框架会处理绘制过程，但是Activity必须提供它的层级布局的根节点。
		</p>
		<p>
			绘制从布局的根节点开始，根节点将测量及绘制整个布局树。绘制过程是遍历整个层级树渲染每一个View中有有效区域的部分。反过来，每一个
			viewgroup都负责请求每一个子View来绘制(通过调用
			<code>draw()</code>
			)，然后每一个View对自己负责。因为对于层级树的遍历
			是有顺序的，这意味着父View会在子View之前绘制，它的兄弟节点将根据在层级树中出现的顺序依次绘制。
		</p>
		<p>
			绘制布局(layout)经过两个过程：一个是测量一个是布局。测量步骤在
			<code>measure(int,int)</code>
			中实现，并且并且是对view层级树至顶向个的遍历。
			每一个view在递归遍历中将尺寸声明向下传递。在测量过程之后，每一个View都存储了自己的尺寸测量信息。 第二个步骤是在
			<code>layout(int,int,int,int)</code>
			中进行，同样是至顶向下的。在这一过程中，每一个父节点负责使用在测量过程中计算出的尺寸信息来放置它所有的 子节点。<br /> <q>
				Android框架不会绘制不在有效区域的View。但是还是会好好的在后台处理好这些View。如果需要强制绘制这些View，可以调用 <code>invalidate()</code>来实现。
			</q>
		</p>
		<p>
			当一个View的
			<code>measure()</code>
			方法返回了，它的以及它的后代View。
			<code>getMeasureWidth()</code>
			和
			<code>getMeasureHeight()</code>
			值必须设置。一个View的测量宽度及高度必须考虑父View的会提供限制。这可以保证在测量过程的最后，父View都会接收所有子View的测量值。一个父View对子View调用
			<code>measure()</code>
			不只一次，例如当父View使用不同的声明尺寸来找出子View需要多大的尺寸，如果所以子View未限制的尺寸太大了或者太小了，父View将用实现的数值重新在子View中调用
			<code>measure()</code>
			(也就是说，如果子View自己对他们可以得到尺寸空间不满意，父View将干预并在第轮中设置规则。)
		</p>
		<p>
			测量过程使用两个类来交流尺寸。
			<code>View.MeasureSpec</code>
			被View用于告诉父View他们想要多大的尺寸及怎么放置。 基本的
			<code>LayoutParams</code>
			类，描述了View在宽度及高度上想要多大。每对于一个尺寸，可以由下面的数值指定：
		<ul>
			<li>一个具体的值</li>
			<li><code>FILL_PARENT(MATCH_PARENT)</code>，意味着View想要跟父View一样大（最小的内边距），在android
				api 8开始使用<code>MATCH_PARENT</code>这一常量，因为更符合语义。</li>
			<li><code>WRAP_CONTENT</code>，意味着这个View只要包围内容的大小(加内边距)</li>
		</ul>
		ViewGroup的不同子类有不同的
		<code>LayoutParams</code>
		子类，例如
		<code>RelativeLayout</code>
		有它自己的
		<code>LayoutParams</code>
		子类， 它包括了将子View水平及垂直居中的能力。
		</p>
		<p>
			<code>MeasureSpecs</code>
			用于从父View向子View传递测量需求。一个
			<code>MeasureSpec</code>
			包含下面三个模式:
		<ul>
			<li><code>UNSPECIFIED:</code>这个被父View用于决定子View想要的尺寸。例如一个<code>LinearLayout</code>
				也许会调用<code>measure()</code>，并将height指定为<code>UNSPECIFIED</code>并且宽度为一个<code>EXACTLY</code>
				240值，来判断子View在给定240像素宽时需要多高。</li>
			<li><code>EXACTLY：</code>用于父View给子View一个指定的尺寸。子View必须使用这个尺寸值。并且保证它所以的后代子View填充这个尺寸。</li>
			<li><code>AL_MOST：</code>，用于父View给子View传递一个最大的尺寸值。子View必须保证它和它所以的后代将填充这个尺寸。</li>
		</ul>
		</p>
	</article>
	<!--  -->
	<article class="paging">
		<h1>任务及回退栈</h1>
<ul>
  <li>所有的activity属于某一个任务。</li>
  <li>一个任务包含与用户交互的activity集合。</li>
  <li>任务能够在后台保留用户的交互状态。</li>
</ul>
<p>
 一个应用通过包含多个<code>activity</code>，每一个activity都应该围绕执行特定的用户操作或者启动其它activity来设计。例如，一一个邮件应用
 也许会有一个activity来显示新邮件的列表，当用户选择一个邮件时，一个新的activity打开用来查看邮件。
</p>
<p>
	一个activity可以打开设备其它应用中的activity。例如，如果你的应用想要发送一封邮件，你可以定义一个Intent(意图)来执行一个"send"操作，同时包含一些数据，
	例如邮件地址，和一条信息。一个来自其它应用的把自己定义成能够处理这些Intent的activity将打开。在这种情况下，intent就是发送邮件，因此一个邮件应用中的"撰写"activity
	将启动(如果有多个activity支持同样的intent，系统会让用户选择使用哪一个)。当邮件发送出去之后，你自己的actiivty将被恢复，并且看起来好像邮件应用中的activity好像你自己应用中的一部分。
	虽然，activity也许来自不同的应用，但是Android系统维持在同一个任务中的无缝用户操作体验。
</p>
<p>
 一个任务就是用户操作某一项工作与之交互的activity集。activity被组织在一个栈中(称为回退栈)，以activity打开时间排序。
</p>
<p>
 设备的Home屏幕是大多数任务开始的地方。用用户触摸在应用程序启动器中的一个图标时(或者Home屏幕中的快捷方式)时，应用的任务将启动到前台。如果此应用还没有已经存在的任务（即此应用最近没有被打开过)
，这时一个新的任务将创建，应用的主activity也会作为任务栈中的根activity打开。</p>

<p>
  当一个当前的activity启动另一个时，新的activity会被压到栈顶并且获得焦点。前一个activity依然在栈中，但是处于停止状态。当一个activity停止时，系统将用户界面的当前状态。
  当用户按Back按键时，当前activity从任务栈栈顶中弹出(activity被销毁)同时以前的activity恢复(之前的UI状态被恢复)。在栈中的Activity不会被重排，仅仅只是从栈中压入和弹出，被当前activity
  打开的将压入栈，用户使用Back按键离开时将弹出栈。如此，回退栈执行像一个“后进先出”的对象结构。
</p>
<p>
当用户持续按Back键时，在栈中的Activity一个个被弹出来显示前面的，直到用户回去Home屏幕(或者用户在启动这个任务时运行的activity)，当所有的activity都从栈中移除时，任务将不在存在。
</p>

<p>
 一个任务是一个耦合的单元，当用户打开新的任务或者回到Home屏幕时能够移动到后台，同时所有的activity处于停止状态，但是任务栈的状态依然保留着，只是任务失去了焦点。
 任务能够返回前台，并保留用户离开时的状态。例如，当前的任务(任务A)有三个activity在任务栈中--两个在当前的activity中。用户按下了Home键，然后人应用程序启用器中启动了一个新的应用。
 当出现Home屏幕时，任务A转到后台。当新的应用启动时，系统为新的应用启动一个任务（任务B)-带有它自己的acitivity栈。与新的应用交互完之后，用户再次返回Home屏幕并且打开启动任务A的应用，现在任务A
 回到前台--任务栈中的所有activity都是完好的，栈顶的activity恢复状态。在这一点上，用户能够通过返回Home屏幕同时选择打开新的应用来启动任务B，这是Android多任务的实例。
</p>
<q>多个任务只能在后台保存一次。但是当用户同时运行了很多后台任务，系统将开始销毁一些后台activity以释放内存，这将会引起activity状态的丢失。</q>
<p>
 因为在任务回退栈中睥activity是不会被重排的，所以如果你的应用允许从多个activity中打开某一个activity，那个activity的新实例将被创建，并且压放任务栈中（
 而不将之前的任务栈中存在的activity带到任务栈顶来）。如此，你应用中的某一个activity将被实例化多次(也许是来自不同的任务)，当用户按Back键返回时，activity的实例将依次出现。
 但是，如果你不想让一个activity实例化多次的话，你可以修改这个默认的行为。参考后面关于管理任务的讨论。
</p>
<p>
 总结默认的activity及任务的行为如下：
</p>
<ul>
	<li>当activityA启动activityB时，activity A停止，但是系统依然保留A的状态(例如，滚动务的位置，表单中的文本)。如果用户在B按Back键返回时A及其状态将恢复。</li>
	<li>当用户通过按Home键离开一个任务，当前acitivity被停止，它的任务将转到后台。系统保留任务栈中每一个activity的状态。如果用户重新打开此应用，此任务将转回前台，
	同时恢复处于栈顶的activity。</li>
	<li>如果用户按Back键，当前的activity从栈中弹出并被销毁。任务栈中的前一个activity将恢复。当一个activity被销毁时，系统并不保留activity的状态。</li>
	<li>Acitivity可以被实例化多次，甚至从不同的任务中。</li>
</ul>

		<div data-role="collapsible" data-theme="a">
			<h2>保护活动状态(Saving Activity State)</h2>
			<p>
			 正如上面讨论的那样，当一个activity停止时，系统默认行为是将保证它的状态。这样，当用户再导航回到前面的activity时，就跟用户该activity时
			 是一样的。但是，你可以，也应该主动的使用回调方法保存activity的状态，以防activity被销毁的需要重新创建。
			</p>
			<p>
				当系统停止你的其中的一个activity的时候(例如当一个新的activity启动或者任务移向后台),系统在它需要回收内存的时候可能将这个activity完全销毁。
				当这种情况发生时，关于此activity的状态信息将丢失。虽然这样，系统还是会知道此activity在后退任务栈中占有一个位置。但是当系统将此activity带向任务栈顶时，系统必须
				重新创建它(而不是恢复它)。为了避免丢失用户工作，你应该主动的在你的activity中实现<code>onSaveInstanceState()</code>回调方法来保存用户工作状态信息。
			</p>
		</div>
		<div data-role="collapsible" data-theme="a">
			<h2>管理任务(Managing Tasks)</h2>
			<p>
				Android管理任务及回退栈的方式，正如上面所提到的--通过将顺次启动的放置在同一个任务及"后进，先出"的栈--这对于大多数应用来说工作得良好，同时你不需要
				关心你的activity如何与任务相关联或者他们在回退栈中如何存在。但是，你也许希望来打破这种默认的行为模式。
				也许你想要你的应用中的一个activity能启动一个新的任务（而不是放置在当前的任务栈中）；或者当你启动一个activity时，你想将一个已经存在的此activity的实例
				带到前台来(而不是在任务栈顶中创建一个新的实例);或者你想当用户离开此任务时清除除了根activity之外的所有的activity。
			</p>
			<p>
			 你可以做到这些，并且可以做更多，通过在<code>&lt;activity&gt;</code>中使用属性，或者在传递给<code>startActivity()</code>中的intent中使用标志。
			</p>
			<p>
			  在这方面，你可以使用<code>&lt;activity&gt;</code>的主要属性如下：
			</p>
			<ul>
			<li><code>taskAffinity</code></li>
			<li><code>launchMode</code></li>
			<li><code>allowTaskReparenting</code></li>
			<li><code>clearTaskOnLaunch</code></li>
			<li><code>alwaysRetainTaskState</code></li>
			<li><code>finishOnTaskLaunch</code></li>
			</ul>
			<p>同时，主要的intent标志如下：</p>
			<ul>
			<li><code>FLAG_ACTIVITY_NEW_TASK</code></li>
			<li><code>FLAG_ACTIVITY_CLEAR_TOP</code></li>
			<li><code>FLAG_ACTIVITY_SINGLE_TOP</code></li>
			</ul>
			<p>
				在下面的章节中，你将了解如何使用这些清单文件属性或者intent标志来定义activity如何与任务相关联及在回退栈中有怎样的行为。
			</p>
			<q>
				<strong>警告：</strong>大多数的应用都不应该打破activity及任务的默认的行为。如果你觉得你的activity有必要修改它的默认行为的话，
				请注意并测试确保在启动及用户通过Back按键从其它activity导航回到此activity时，此activity的可用性。确保测试导航行为跟用户期待的行为不冲突。
			</q>
		</div>
		<div data-role="collapsible" data-theme="a">
			<h2>定义启动模式(Defining launch modes)</h2>
			<p>启动模式允许你定义一个活动的新的实例如何与当前的任务相关联。 
			你可以通过两种方式来定义不同的启动模式：
			 </p>
			 <ul>
			 	<li><strong>使用清单文件</strong>，当你在你的清单文件中声明一个activity时，你可以指定当activity启动时，它与任务如何关联</li>
			 	<li><strong>使用Intent标志</strong>，当你调用<code>startActivity()</code>时，你可以在<code>Intent</code>中包含一个标志，声明是否，或者如何将新的activity与当前的任务相关联。</li>
			 </ul>
			 <p>
			 	如此，如果activity A启动Activity B，Activity B能够在它的清单文件中定义它将如何与当前任务栈相关联，同时Activity A也能够请求
			 	 Activity B将如何与当前任务关联起来。如果两个activity都定义了Activity该如何与任务相关联，那么Activity A的请求(定义在Intent中)将比
			 	 Activity B的请求(定义在清单文件中)具有更高的优先级。
			 	 <q><strong>注意：</strong>有些在清单文件中可用的启动模式在Intent的标志中并不可用，反过来，某些在Intent可用的标志的启动模式不能定义在清单文件中。</q>
			 </p>
			 	<div data-role="collapsible" data-theme="a">
					<h5>使用清单文件(Using the manifest file)</h5>
					
					<p>
						当在你的清单文件中声明一个activity时，你可以通过使用<code>&lt;actiivty&gt;</code>元素的<code>launchMode</code>属性
						来指定此activity将如何与一个task相关联。
					</p>
					<p>
						<code>launchMode</code>属性指定了一个activity将如何启动时task的指令。
						你可以<code>launchMode</code>赋以下四个属性值：
					</p>
					<ul>
					<li><code>"standard"</code>，默认模式，默认值。系统将在activity启动的地方在任务栈中创建一个新的实例，并传递intent给它。
					activity可以被实例多次，每一个实例可以属性不同的任务，同一个任务也可以有多个实例。</li>
					<li><code>"singleTop"</code>如果一个活动已经存在当前任务栈中顶部时，系统将通过调用onNewIntent()将Intent定向传递到那一个活动的实例。
						而不是重新创建一个。这个活动可以被创建多次，每一个实例可以属于不同的任务。同一个任务也可以拥有多个实例（不能是在栈顶部）。
						<p>
							例如，假设任务栈由一个根activity A，activity B,C和D组成，D在栈顶。(栈为A-B-C-D;D在栈顶)。此时到来一个请求
							D类型的activity。如果D有默认的"standard"启动模式，那么此类的一个新的实例将被创建，此时栈变成了A-B-C-D-D.
							但是，如果D的启动模式是"singleTop"，已经存在的D的实例将通过<code>onNewIntent()</code>来接收新的intent，因为它在栈顶--
							栈依然是A-B-C-D。但是，如果你到来的是一个请求B类型的activity。即使B的启动模式是"singleTop"，B的新实例将被添加到栈中。
							<q>
								<strong>注意：</strong>当一个activity的新实例被创建的时候，用户能按Back键返回前一个activity。但是当一个已经存在的activity实例
								处理新的intent时，用户不能通过按Back键返回到在新的intent到达<code>onNewIntent()</code>之前的状态。
							</q>
						</p>
						
						 </li>
					<li><code>"singleTask"</code>，系统创建一个新任务，并实例化新任务的根activity。但是，如果一个activity的实例，已经存在于一个单独的任务
					中，系统将通过调用<code>onNewIntent()</code>，将intent传递给已经存在的实例。而不是创建一具新的任务。同一时刻只能有一个此activity的实例。
						<q><strong>注意：</strong>虽然，此activity在一个新的任务中启动，但是Back按键依然会将用户返回到前一个activity</q>
					</li>
					<li><code>"singleIntance"</code>，除了系统不再启动任何其它activity的实例进activity之外。与"singleTask"相同。
					此activity将一直是它的任务中单独的唯一的实例;所有在此activity中启动的实例都将打开一个新的单独的任务。</li>
					</ul>
					<p>
						作为另一个例子，例如，Android的浏览器应用声明了所有的网络浏览activity将总是在它自己的任务中打开--通过在<code>&lt;activity&gt;</code>
						指定<code>singleTask</code>模式，这意味着，如果你的应用有一个intent去打开Android浏览器，它的activity在你的应用的任务栈中。
						相应，一个新的任务将创建，或者如果浏览器已经有一个任务在后台运行时，该任务将转到前台来处理新的intent。
					</p>
					<p>
						无论一个activity是否在一个新任务中启动，或者与启动它的activity在同一个任务中，Back键都将带用户回到前一个activity中。
						但是，如果你在启动一个activity的时候指定的"singleTask"模式，那么如果一个activity的实例已经在后台任务中存在了，那么整个任务都
						将转到前台。在这一点上，后退栈将包含转到前台任务的所有的activity，并在栈顶。
					</p>
					<p>
						要了解更多关于在清单文件中使用启动模式的信息，参见<code>&lt;activity&gt;</code>元素的文档，那里讨论了更多关于<code>launchMode</code>
						的属性及可接受的值。
						<q><strong>注意：</strong>使用<code>launchMode</code>属性为你的activity指定的的行为，正如下一节将讨论的，可以被启用你的activity的intent包含的标志覆盖。</q>
					</p>
				 </div>
				 <div data-role="collapsible" data-theme="a">
					<h3>使用Intent标志</h3>
					<p>
						当启动一个activity时，你通过在传递给<code>startActivity()</code>的intent中包含标志来修改一个activity和它的任务的默认关系。
						可用于修改默认关系的标志如下：
					</p>
					 <ul>
					 	<li><code>FLAG_ACTIVITY_NEW_TASK</code>在一个新任务中启动此activity。如果你正在启动的activity已经有一个任务在运行了，此任务将
					 	转到前台，保留着最后的状态，同时此activity将通过<code>onNewIntent()</code>接收新的intent。
					 	这个与在前面一节中讨论的"singleTask"启动模式效果一样。</li>
					 	<li><code>FLAG_ACTIVITY_SINGLE_TOP</code>，如果一个活动已经存在当前任务栈中顶部时，系统将通过调用onNewIntent()将Intent定向传递到那一个活动的实例。
						而不是重新创建一个。与启动模式"singleTop“的效果是一样的。</li>
					 	<li><code>FLAG_ACTIVITY_CLEAR_TOP</code>如果此被启动的 activity已经在当前任务中运行，此时并不会创建此Activity的新实例，而是在它顶部的其它activity都将被销毁，
					 	同时此activity的实例被恢复(现在在栈顶了)并通过<code>onNewIntent()</code>来接收传递给它的intent。
					 	<p>在<code>launchMode</code>属性中没有对应的值来产生此效果。</p>
					 	<p>
					 		<code>FLAG_ACTIVITY_CLEAR_TOP</code>通过与<code>FLAG_ACTIVITY_NEW_TASK</code>联合使用。当一起使用时，这些标志
					 		是一种定位已经在另一个任务栈中的activity，并处于能够响应intent的位置。
					 		<q>
					 			<strong>注意：</strong>如果指定的activity的启动模式是"standard"，它同样将从此栈中移除，同时启动一个新实例在它的位置来处理
					 			到来的intent。这时因为当启动模式是<code>"standard"</code>时，会为每一个新intent创建一个新实例。
					 		</q>
					 	</p>
					 	</li>
					 </ul>
				</div>
		</div>



		<div data-role="collapsible" data-theme="a">
			<h2>处理连结关系（Handling affinities）</h2>
			<p>
				连结(affinity)一词说明，一个activity希望属于哪一个任务。默认情况下，同一个应用的所有activity都互相有一个连结。
				因此，默认情况下，同一个应用的所有activity都倾向于在同一个任务中。但是，你可以修改activity的这种默认的行为。定义在不同
				应用中的activity可以共享同一个连结，或者在同一个应用中的activity可以有不同的任务连结。
			</p>
			<p>
				对于给定的activity，可以通过<code>&lt;activity&gt;</code>的<code>taskAffinity</code>属性来修改连结性。
			</p>
			<p>
				<code>taskAffinity</code>属性，接受一个字符串，它必须在定义在<code>&lt;manifest&gt;</code>中的默认包名中是唯一的，
				因为系统通过此名字来识别此应用的默认连结关系。
			</p>
			<p>
				连结关系在下面两种情况下发挥作用：
			</p>
			<ul>
				<li>当启动一个activity的intent包含FLAG_ACTIVITY_NEW_TASK标志时。<br/>
					一个新activity默认情况下是，启动时调用<code>startActivity()</code>的activity的任务栈。它将跟调用者一样压入栈。
					但是，如果传递给<code>startActivity()</code>的intent包含FLAG_ACTIVITY_NEW_TASK标志时，系统将查找一个不同的任务来安置
					此新activity。通常，它是一个新的任务。但是，并不一定是。如果存在与新activity同样的连结关系的任务的话，此activity将启动时那一个任务中。
					 如果不是，那将启动一个新的任务。
					 <p>
					  如果此标志使一个activity创建一个新任务，用户按Home键离开时，则必须有相同的方式让用户导航回那一个任务。一些实体(例如通知管理器)总是
					  可以在外部的任务中启动activity，而不作为自己的的一部分，所以它们问题将
					  在它们传递给<code>startActivity()</code>的intent中放置FLAG_ACTIVITY_NEW_TASK标志。如果你有一个activity可以被一个外部
					  的实体调用，也许使用这个标志，注意用户有一个独立方式来返回到它启动的任务中，
					  例如一个启动器图标(一个任务的根activity有一个<code>CATE_GORY_LAUNCHER</code>的intent filter;参见下面的章节。)
					 </p>
				</li>
				<li>当一个activity的<code>allowTaskReparenting</code>属性设置为<code>"true"</code>如<br/>
					<p>在这种情况下，activity可以从启动它的任务中移到到有一个连结的任务中--当那个任务转移到前台时。</p>
					<p>
						例如，假设一个报告所选择城市天气情况的activity定义为一个旅游应用的一部分。
						它与应用中的其它activity有相同的连结关系(默认的应用连结关系)，同时它通过此属性允许"re-parenting"。当你的一个activity启动
						天气预报activity时，它初始为与你的activity相同的任务。但是，当这个旅游应用转移到前台时，此天气预报activity被重新赋值为那一个任务，
						并且在其中显示。
					</p>
					<q>
						<strong>提示：</strong>如果一个<code>.apk</code>文件在用户眼中包含多个应用，你可能需要使用<code>taskAffinity</code>
						属性来给关联到不同的"应用"不同的连结关系。
					</q>
				</li>
			</ul>
		</div>
		<div data-role="collapsible" data-theme="a">
			<h2>清除任务回退栈（Clearing the back stack)</h2>
			<p>如果离开一个任务很长时间，系统会将此任务除根activity之外的所有activity清除。当用户再次返回到那个activity时，只有根activity被恢复。
			  系统这样做是因为，在长时间之后，用户更喜欢丢弃他们之前的状态，同时返回到任务中开始新东西 。
			  </p>
			  <p>下面有几个activity的属性可以修改这种默认的行为。</p>
			  <ul>
			  	<li><code>alwaysRetainTaskState</code>如果一个任务中的根activity的此属性设置为<code>"true"</code>，上面描述的默认行为将不会发生。
			  	任务在它的栈中所有的activity甚至在长时间后也是如此。</li>
			  	<li><code>clearTaskOnLaunch</code>，如此任务的根activity的此属性设置为<code>"true"</code>，无论何时当用户离开此任务然后返回到此任务时，此任务栈将清除除根activity之外的所有activity.
			  		换一句话说，它与<code>alwaysRetainTaskState</code>的行为相反。用户将返回到此任务的初始状态，甚至用户只是离开了一会。
			  	</li>
			  	<li><code>finishOnTaskLaunch</code>，这个属性像<code>clearTaskOnLaunch</code>，但是它作用于单独的一个activity，而不是整个任务。
			  		它可以使任何activity离开，包含根activity。当此属性设置为<code>"true"</code>时，对于当前的会话来讲它还是任务中的一部分，
			  		但是当用户离开此任务再返回时，此activity已经不存在了。
			  	</li>
			  </ul>
		</div>
		<div data-role="collapsible" data-theme="a">
			<h2>启动一个任务（Start a task)</h2>
			<p>
			 你可以设置一个activity作为一个任务入口点，方法是给它的意图过滤器指定一个像这样的的action：<code>"android.intent.action.MAIN"</code>
			 和一个像这样的category:<code>"android.intent.category.LAUNCHER"</code>。例如：
			</p>
			<pre>
&lt;activity ... &gt;
    &lt;intent-filter ... &gt;
        &lt;action android:name="android.intent.action.MAIN" /&gt;
        &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
    &lt;/intent-filter&gt;
    ...
&lt;/activity&gt;
</pre>
<p>
 一个这样的意图过滤器，将使得此activity的标签及图标显示在应用程序启动器中，让用户有一个启动此activity的方式，及在它启动之后的任意时间里返回此任务。
</p>
<p>
 第二项特性很重要：用户必须能够离开一个任务，然后再通过此activity启动器再回来。考虑到这个原因，使activity总是初始化任务两个启动模式，
 <code>"singleTask"</code>和<code>"singleInstance"</code>，将被用在当此activity有一个<code>ACTION_MAIN</code>
 并且一个<code>CATEGORY_LAUCHER</code>过滤器时，例如，如果没有此过滤器将会发生什么，一个intent启动了一个"singleTask"的activity，初始化了一个新task，
 用户在这个新task上工作了一段时间。然后用户按下了Home键。此任务这里被转到了后台，并且不可见了。此时用户没有办法再返回到那个任务中，因为它没有出现在应用程序启动器中。
</p>
<p>
如果你不想让用户可以返回一个活动，可以设置<code>&lt;activity&gt;</code>元素的<code>finishOnTaskLaunch</code>为<code>"true"</code>。
</p>
		</div>
	</article>
	<!-- end 任务及回退栈  -->
	<article class="paging">
		<h1>无线局域网</h1>
 <div class="sub_section">
                <h2 class="sub_section_name">技术结构</h2>
                <dl>
                    <dt><h3 class="tech_term">站点(station)</h3></dt><dd>在一个网络中，所以组件能够连接到的中央媒介被称作为站点。所有的站点都是与无线网络接口控制器(wireless network interface controllers,WNICs)平级。站点有两种类型:访问点(access points)和客户端(clients)。访问点(APs)，一般来说即路由，是无线网络的基站。他们传输和接收无线电波来使无线设备能够互相通信。无线客户端可以是移动设备如笔记本，个人数字助力，IP 电话及其它智能机，或者是配备了无线网卡的固定设备如桌面电脑和工作站。</dd>
                     <dt><h3 class="tech_term">关口(Portal)</h3></dt><dd>用于将无线局域网和有线局域网或其它网络连接起来。<sup>[2]</sup></dd>
                     <dt><h3 class="tech_term">基本服务单元(Basic service set，BSS)</h3></dt><dd>一个基本服务单元（以下简称BSS)中的所有站点都可以相互通信。每一个BSS都有一个称作BSSID的标识符，它是BBS访问点的物理地址。<br/> 有两种类型的BSS：独立BSS（或称这为IBSS)是一个ad-hoc网络，它没有访问点，也就意味着它不能接入其它的BSS</dd>
                      <dt><h3 class="tech_term">扩展服务单元(Extend service set,ESS)</h3></dt><dd>扩展服务单元（以下简称ESS)是一组连接的BSS。在ESS中，访问点通过分发系统连接。每一个ESS都有一个标识符(ID)称之为SSID，它是一个最大32字节的字符串。</dd>
                      <dt><h3 class="tech_term">分发系统(Distribution System,DS)</h3></dt><dd>分发系统（以下简称DS）连接ESS中的访问点（APs)。DS的概念用于通过漫游(roaming)增加网点的网络覆盖率。<br/>DS可以是有线的也可以是无线的。当前无线DS主要基于WDS或者MESH协议，但是也有其它协议。</dd>
                
                </dl>
                <p></p>
             </div><!-- end of 1.3 -->
             
             <div class="sub_section">
                <h2 class="sub_section_name">无线局域网的类型</h2>
                    <div class="sub_sub_section">
                     <h3 class="sub_sub_section_name">点对点（Peer-to-peer)</h3>
                     <p>
                        一个ad-hoc是一个仅仅用于点对点(P2P)通信的站点。没有站点也没有谁为会话分配权限。它通过独立基本服务单元(BSS)实现。
                     </p>
                     <p>
                        一个点对点(P2P)网络允许无线服务两者之间直接相联。无线设备之间能够在一定范围内互相识别与直接建立连接，并不需要中间访问点。这种方法一般通常用于两台计算机相连以组建网络。
                     </p>
                     <p> 在这种情况下如果使用了信号强度计量，它读取信号强度也许不准确，还很容易出错，因为它注册了最强的信号强度，它也许是最近的计算机的。</p>
                       <p> 
                          IEEE 802.11定义了物理层(Physical layer,PHY)和媒介访问层(Media Access Control,MAC)，它们都基于CSMA/CA(Carrier Sense Multiple Access with Collision Avoidance，载波侦听多路访问)。802.11 规范包含了尽量减少冲突的规定，因为两个移动设备单位可能都在一个共同访问点范围内，但是在各自的范围外。
                       </p>
                       <p>
                         802.11有两种基础的操作模式：ad-hoc模式和基础架构模式。在ad-hoc模式中，移动设备单位直接点对点的传输。
                         在基础架构模式下，移动设备单位通过一个访问点进行通信，访问点充当与有线网络架构的连接桥。因为相比有线连接而言无线通信使用了开放的连接介质，802.11的设计者们同样考虑了共享密钥加密机制:Wired Equivalent Privacy(WEP),Wi-Fi Protected Access(WPA,WPA2),来保证无线网络连接的安全性。
                       </p>
                    </div>
                    
                     <div class="sub_sub_section">
                         <h3 class="sub_sub_section_name">连接桥（Bridge)</h3>
                         <p>
                            一个连接桥，一般用来连接不同类型的网络。一个无线的以太网连接桥允许设备建立从有线以太网到无线网络的连接。连接桥充当到无线局域网的连接点。
                         </p>
                    </div>
                    
                   <div class="sub_sub_section">
                     <h3 class="sub_sub_section_name">无线分发系统(Wireless distribution system，WDS)</h3>
                     <p>
                        在一个802.11网络中，无线分发系统（以下简称WDS)使用于访问点的内部连接。它 允许一个无线网络通过使用多个访问点来扩展，而不需要有线的支持。相对于传统的网络来说，WDS显著的优势就是无线在访问点的链接中它保留了客户端报文的MAC地址。
                     </p>
                     <p>访问点可以是一个主的，中继站点，的或者远程的基站。主基站通常连接到一个有线以太网，一个中继基站在远程基站，无线客户端或者其它中继基站传递数据到主基站或者其它中继基站。远程基站从无线客户端中接受连接，并将其传递到其它中继基站或者主基站去。客户端的连接通过MAC地址而不是指定IP值。</p>
                     <p>
                        WDS中的所有基站必须配置成同样的无线电波频率。并且，如果使用了WEP密钥或者WPA密钥的话，要共享。它们可以配置成不同的服务单元标识符。WDS同样需要基站配置成向其它基站转发。
                     </p>
                     <p>
                        WDS有时可能看作一个集线器，因为它看起来在同时接受和桥接无线客户端（这一点不想传统的连接桥）。值得注意的是，在这种方法中，所以无线连接都是对等的。
                     </p>
                     <p>
                        在网络中如果很难通过有线连接所有的访问点，可以考虑使用将访问点作为集线器。
                     </p>
                    </div>
                    
     
               
             </div><!-- end of 1.4 -->
             
             
            <div class="sub_section">
                <h2 class="sub_section_name">漫游（Roaming)</h2>
                <div>
                    对于无线局域网来说漫游有两种定义:
                    <ol>
                       <li>内部漫游：在一个室内网络中，由于信号强度太弱了，移动基站(Mobile Station,MS)（以下简称MS)从一个连接点(AP)到另一个连接点，一个认证服务器(RADIUS)，通过802.1x（即PEAP)自动对MS进行重认证。服务质量的改变发生在室内网络中。MS从一个访问点漫游到另一个访问点时，通常中断MS之间，和连接到此网络应用的的数据传输。MS,例如间断的监视可选访问点（也许某一个可以提供更好的连接）。在某些方面来说基于专有的机制。MS自己决定重新连接到一个无线信号更强的访问点。有时MS可能与访问点失去连接，因为还没有跟另一个访问点连接上。为了为应用提供可靠的连接，MS一般会包括提交持久化会话的软件。</li>
                       <li>外部漫游（External Roaming)：MS进入到另一个无线网络服务提供商的一个无线局域网中，并使用了其服务（Hotspot)。用户能够将它的网络与另一个外部网络独立出来，如果这对访问者是开放的话。对于外部网络的移动服务必须有一个认证及计费系统。</li>
                   </ol>
                </div>
             </div>
	</article>
	<!--  -->
</body>
</html>
